package com.rs.game.player.content;

import java.util.concurrent.CopyOnWriteArrayList;

import com.rs.cache.loaders.ItemDefinitions;
import com.rs.game.item.Item;
import com.rs.game.player.Player;
import com.rs.game.player.content.grandExchange.GrandExchange;
import com.rs.utils.ItemExamines;
import com.rs.utils.ItemSetsKeyGenerator;

public class Shop {

	private static final int MAIN_STOCK_ITEMS_KEY = ItemSetsKeyGenerator.generateKey();

	private static final int MAX_SHOP_ITEMS = 40;
	public static final int COINS = 995;

	private String name;
	private Item[] mainStock;
	private int[] defaultQuantity;
	private Item[] generalStock;
	private int money;
	private CopyOnWriteArrayList<Player> viewingPlayers;

	public Shop(String name, int money, Item[] mainStock, boolean isGeneralStore) {
		viewingPlayers = new CopyOnWriteArrayList<Player>();
		this.name = name;
		this.money = money;
		this.mainStock = mainStock;
		defaultQuantity = new int[mainStock.length];
		for (int i = 0; i < defaultQuantity.length; i++)
			defaultQuantity[i] = mainStock[i].getAmount();
		if (isGeneralStore && mainStock.length < MAX_SHOP_ITEMS)
			generalStock = new Item[MAX_SHOP_ITEMS - mainStock.length];
	}

	public static int [][] DonationItems = { {1038, 25}, {1040, 25}, {1042, 25}, {1044, 25}, {1046, 25}, {1048, 25}, {1053, 15}, {1055, 15}, {1057, 15},
		{1050, 10}, {21473, 20 , 21474, 21475, 21476, 21472 }, {21468, 20, 21469, 21470, 21471, 21467}, {21463, 20, 21464, 21465, 21466, 21462 } };

	public static int[][] loyaltyPrices = { { 22298, 5000 }, { 23862, 5000 },
		{ 22925, 5000 }, { 23852, 5000 }, { 22909, 5000 },{ 22903, 5000 }, 
		{ 20068, 3500 }, { 6729, 150 }, { 15332, 50 }, 
		{ 10548, 3750 }, { 10551, 4250 },{ 12512, 2500 }, { 12514, 2500 }, 
		{ 12516, 2500 }, { 12518, 2500 },{ 12520, 2500 }, { 12522, 2500 }, 
		{12469, 5000}, {12471, 5000}, {12473, 5000}, {12475, 5000}, {4151, 3500} };

	public static int[][] Voteprices = { {17295, 80}, {10887, 45},{15834, 25}, {15835, 75}, // armour and weapons
		{1037, 15}, {6666, 5}, {18706, 50}, {18707, 40}, {18708, 20}, {18709, 30}, {21580, 15}, {23674, 40}, {18667, 50}, {18743, 25}, {18744, 20},
		{18745, 20}, {18746, 20} }; //cosmetic

	public boolean isGeneralStore() {
		return generalStock != null;
	}

	public void addPlayer(final Player player) {
		viewingPlayers.add(player);
		player.getTemporaryAttributes().put("Shop", this);
		player.setCloseInterfacesEvent(new Runnable() {
			@Override
			public void run() {
				viewingPlayers.remove(player);
				player.getTemporaryAttributes().remove("Shop");
				player.getTemporaryAttributes().remove("shop_transaction");
				player.getTemporaryAttributes().remove("isShopBuying");
				player.getTemporaryAttributes().remove("ShopSelectedSlot");
				player.getTemporaryAttributes().remove("ShopSelectedInventory");
			}
		});
		player.refreshVerboseShopDisplayMode();
		player.getVarsManager().sendVar(118, generalStock != null ? 139 : MAIN_STOCK_ITEMS_KEY); 
		player.getVarsManager().sendVar(1496, -1); // sample items container id (TODO: add support for it)
		player.getVarsManager().sendVar(532, money);
		resetSelected(player);
		sendStore(player);
		player.getInterfaceManager().sendInterface(1265); // opens shop
		resetTransaction(player);
		setBuying(player, true);
		if (generalStock != null)
			player.getPackets().sendHideIComponent(1265, 19, false); // unlocks general store icon
		player.getPackets().sendIComponentSettings(1265, 20, 0, getStoreSize(), 1150); // unlocks stock slots
		sendInventory(player);
		player.getPackets().sendIComponentText(1265, 85, name);
	}

	public void resetTransaction(Player player) {
		setTransaction(player, 1);
	}

	public void increaseTransaction(Player player, int amount) {
		setTransaction(player, getTransaction(player) + amount);
	}

	public int getTransaction(Player player) {
		Integer transaction = (Integer) player.getTemporaryAttributes().get("shop_transaction");
		return transaction == null ? 1 : transaction;
	}

	public void pay(Player player) {
		Integer selectedSlot = (Integer) player.getTemporaryAttributes().get("ShopSelectedSlot");
		Boolean inventory = (Boolean) player.getTemporaryAttributes().get("ShopSelectedInventory");
		if (selectedSlot == null || inventory == null)
			return;
		int amount = getTransaction(player);
		if (inventory)
			sell(player, selectedSlot, amount);
		else
			buy(player, selectedSlot, amount);
	}

	public int getSelectedMaxAmount(Player player) {
		Integer selectedSlot = (Integer) player.getTemporaryAttributes().get("ShopSelectedSlot");
		Boolean inventory = (Boolean) player.getTemporaryAttributes().get("ShopSelectedInventory");
		if (selectedSlot == null || inventory == null)
			return 1;
		if (inventory) {
			Item item = player.getInventory().getItem(selectedSlot);
			if (item == null)
				return 1;
			return player.getInventory().getAmountOf(item.getId());
		} else {
			if (selectedSlot >= getStoreSize())
				return 1;
			Item item = selectedSlot >= mainStock.length ? generalStock[selectedSlot - mainStock.length] : mainStock[selectedSlot];
			if (item == null)
				return 1;
			return item.getAmount();
		}
	}

	public void setTransaction(Player player, int amount) {
		int max = getSelectedMaxAmount(player);
		if (amount > max)
			amount = max;
		else if (amount < 1)
			amount = 1;
		player.getTemporaryAttributes().put("shop_transaction", amount);
		player.getVarsManager().sendVar(2564, amount);
	}

	public static void setBuying(Player player, boolean buying) {
		player.getTemporaryAttributes().put("isShopBuying", buying);
		player.getVarsManager().sendVar(2565, buying ? 0 : 1);
	}

	public static boolean isBuying(Player player) {
		Boolean isBuying = (Boolean) player.getTemporaryAttributes().get("isShopBuying");
		return isBuying != null && isBuying;
	}

	public void sendInventory(Player player) {
		player.getInterfaceManager().sendInventoryInterface(1266);
		player.getPackets().sendItems(93, player.getInventory().getItems());
		player.getPackets().sendUnlockIComponentOptionSlots(1266, 0, 0, 27, 0, 1, 2, 3, 4, 5);
		player.getPackets().sendInterSetItemsOptionsScript(1266, 0, 93, 4, 7, "Value", "Sell 1", "Sell 5", "Sell 10", "Sell 50", "Examine");
	}

	public void buyAll(Player player, int slotId) {
		if (slotId >= getStoreSize())
			return;
		Item item = slotId >= mainStock.length ? generalStock[slotId - mainStock.length] : mainStock[slotId];
		buy(player, slotId, item.getAmount());
	}

	public static int DCreditsShop = 0;
	public static int loyaltyShop = 0;
	public static int VoteShop = 0;

	public void buy(Player player, int slotId, int quantity) {
		if (slotId >= getStoreSize())
			return;
		Item item = slotId >= mainStock.length ? generalStock[slotId - mainStock.length] : mainStock[slotId];
		if (item == null)
			return;
		if (item.getAmount() == 0) {
			player.getPackets().sendGameMessage("There is no stock of that item at the moment.");
			return;
		}
		if (money != 995) {
			for (int i11 = 0; i11 < DonationItems.length; i11++) {
				DCreditsShop = 1;
				if (item.getId() == DonationItems[i11][0]) {
					if (player.getDCredits() < DonationItems[i11][1] * quantity) {
						player.getPackets().sendGameMessage("You need <col=FF0000>" + DonationItems[i11][1] + "</col> DCredits to buy this item!");
						return;
					} else
						DCreditsShop = 1;
					if (DonationItems[i11][0] == 21473) {
						if (player.getInventory().getFreeSlots() >= 5) {
							player.getInventory().addItem(DonationItems[i11][0], 1);
							player.getInventory().addItem(DonationItems[i11][2], 1);
							player.getInventory().addItem(DonationItems[i11][3], 1);
							player.getInventory().addItem(DonationItems[i11][4], 1);
							player.getInventory().addItem(DonationItems[i11][5], 1);
							player.setDCredits(player.getDCredits() - DonationItems[i11][1]);
							player.getPackets().sendGameMessage("You have bought a vanguard armour set from the Donator store.");
							player.getPackets().sendGameMessage("You currently have " + "<col=FF0000>" +player.getDCredits()+ "</col>" + " DCredits!");

						} else {
							player.getPackets().sendGameMessage("You need at least 5 free inventory spaces in order to buy an armour set.");
							return;
						}
					} else if (DonationItems[i11][0] == 21468) {
						if (player.getInventory().getFreeSlots() >= 5) {
							player.getInventory().addItem(DonationItems[i11][0], 1);
							player.getInventory().addItem(DonationItems[i11][2], 1);
							player.getInventory().addItem(DonationItems[i11][3], 1);
							player.getInventory().addItem(DonationItems[i11][4], 1);
							player.getInventory().addItem(DonationItems[i11][5], 1);
							player.setDCredits(player.getDCredits() - DonationItems[i11][1]);
							player.getPackets().sendGameMessage("You have bought a trickster armour set from the Donator store.");
							player.getPackets().sendGameMessage("You currently have " + "<col=FF0000>" +player.getDCredits()+ "</col>" + " DCredits!");

						} else {
							player.getPackets().sendGameMessage("You need at least 5 free inventory spaces in order to buy an armour set.");
							return;
						}

					} else if (DonationItems[i11][0] == 21463) {
						if (player.getInventory().getFreeSlots() >= 5) {
							player.getInventory().addItem(DonationItems[i11][0], 1);
							player.getInventory().addItem(DonationItems[i11][2], 1);
							player.getInventory().addItem(DonationItems[i11][3], 1);
							player.getInventory().addItem(DonationItems[i11][4], 1);
							player.getInventory().addItem(DonationItems[i11][5], 1);
							player.setDCredits(player.getDCredits() - DonationItems[i11][1]);
							player.getPackets().sendGameMessage("You have bought a battle-mage armour set from the Donator store.");
							player.getPackets().sendGameMessage("You currently have " + "<col=FF0000>" +player.getDCredits()+ "</col>" + " DCredits!");

						} else {
							player.getPackets().sendGameMessage("You need at least 5 free inventory spaces in order to buy an armour set.");
							return;
						}
					} else {
						player.getPackets().sendGameMessage("You have bought a " + item.getDefinitions().getName() + " from the Donator store.");
						player.getInventory().addItem(DonationItems[i11][0], 1);
						player.setDCredits(player.getDCredits() - DonationItems[i11][1]);
						player.getPackets().sendGameMessage("You currently have " + "<col=FF0000>" +player.getDCredits()+ "</col>" + " DCredits!");
					}
					return;
				}
			}
			for (int i11 = 0; i11 < loyaltyPrices.length; i11++) {
				loyaltyShop = 1;
				if (item.getId() == loyaltyPrices[i11][0]) {
					if (player.getLoyaltyPoints() < loyaltyPrices[i11][1] * quantity) {
						player.getPackets().sendGameMessage("You need <col=FF0000>" + loyaltyPrices[i11][1] + "</col> loyalty Points to buy this item!");
						return;
					} else
						loyaltyShop = 1;
					player.getPackets().sendGameMessage("You have bought a " + item.getDefinitions().getName() + " from the loyalty store.");
					player.getInventory().addItem(loyaltyPrices[i11][0], 1);
					player.setLoyaltyPoints(player.getLoyaltyPoints() - loyaltyPrices[i11][1]);
					player.getPackets().sendGameMessage("You currently have " + "<col=008000>" +player.getLoyaltyPoints()+ "</col>" + " loyalty points!");
					return;
				}
			}
			for (int i11 = 0; i11 < Voteprices.length; i11++) {
				VoteShop = 1;
				if (item.getId() == Voteprices[i11][0]) {
					if (player.getVotes() < Voteprices[i11][1] * quantity) {
						player.getPackets().sendGameMessage("You need <col=FF0000>" + Voteprices[i11][1] + "</col> Voting Points to buy this item!");
						return;
					} else
						VoteShop = 1;
					player.getPackets().sendGameMessage("You have bought a " + item.getDefinitions().getName() + " from the voting store.");
					player.getInventory().addItem(Voteprices[i11][0], 1);
					player.setVotes(player.getVotes() - Voteprices[i11][1]);
					player.getPackets().sendGameMessage("You currently have " + "<col=FF0000>" +player.getVotes()+ "</col>" + " Voting Points!");
					return;
				}
			}

		}
		int dq = slotId >= mainStock.length ? 0 : defaultQuantity[slotId];
		int price = getBuyPrice(item, dq);
		int amountCoins = money == COINS ? player.getInventory().getCoinsAmount() : player.getInventory().getItems().getNumberOf(money);
		int maxQuantity = amountCoins / price;
		int buyQ = item.getAmount() > quantity ? quantity : item.getAmount();

		boolean enoughCoins = maxQuantity >= buyQ;
		if (!enoughCoins) {
			player.getPackets().sendGameMessage("You don't have enough " + ItemDefinitions.getItemDefinitions(money).getName().toLowerCase() + ".");
			buyQ = maxQuantity;
		} else if (quantity > buyQ)
			player.getPackets().sendGameMessage("The shop has run out of stock.");
		if (item.getDefinitions().isStackable()) {
			if (player.getInventory().getFreeSlots() < 1) {
				player.getPackets().sendGameMessage("Not enough space in your inventory.");
				return;
			}
		} else {
			int freeSlots = player.getInventory().getFreeSlots();
			if (buyQ > freeSlots) {
				buyQ = freeSlots;
				player.getPackets().sendGameMessage("Not enough space in your inventory.");
			}
		}
		if (buyQ != 0) {
			int totalPrice = price * buyQ;
			if (player.getInventory().removeItemMoneyPouch(new Item(money, totalPrice))) {
				player.getInventory().addItem(item.getId(), buyQ);
				item.setAmount(item.getAmount() - buyQ);
				if (item.getAmount() <= 0 && slotId >= mainStock.length)
					generalStock[slotId - mainStock.length] = null;
				refreshShop();
				resetSelected(player);
			}
		}
	}

	public void restoreItems() {
		boolean needRefresh = false;
		for (int i = 0; i < mainStock.length; i++) {
			if (mainStock[i].getAmount() < defaultQuantity[i]) {
				mainStock[i].setAmount(mainStock[i].getAmount() + 1);
				needRefresh = true;
			} else if (mainStock[i].getAmount() > defaultQuantity[i]) {
				mainStock[i].setAmount(mainStock[i].getAmount() + -1);
				needRefresh = true;
			}
		}
		if (generalStock != null) {
			for (int i = 0; i < generalStock.length; i++) {
				Item item = generalStock[i];
				if (item == null)
					continue;
				item.setAmount(item.getAmount() - 1);
				if (item.getAmount() <= 0)
					generalStock[i] = null;
				needRefresh = true;
			}
		}
		if (needRefresh)
			refreshShop();
	}

	private boolean addItem(int itemId, int quantity) {
		for (Item item : mainStock) {
			if (item.getId() == itemId) {
				item.setAmount(item.getAmount() + quantity);
				refreshShop();
				return true;
			}
		}
		if (generalStock != null) {
			for (Item item : generalStock) {
				if (item == null)
					continue;
				if (item.getId() == itemId) {
					item.setAmount(item.getAmount() + quantity);
					refreshShop();
					return true;
				}
			}
			for (int i = 0; i < generalStock.length; i++) {
				if (generalStock[i] == null) {
					generalStock[i] = new Item(itemId, quantity);
					refreshShop();
					return true;
				}
			}
		}
		return false;
	}

	public void sell(Player player, int slotId, int quantity) {
		if (player.getInventory().getItemsContainerSize() < slotId)
			return;
		Item item = player.getInventory().getItem(slotId);
		if (item == null)
			return;
		int originalId = item.getId();
		if (item.getDefinitions().isNoted() && item.getDefinitions().getCertId() != -1)
			item = new Item(item.getDefinitions().getCertId(), item.getAmount());
		if (!ItemConstants.isTradeable(item) || item.getId() == money) {
			player.getPackets().sendGameMessage("You can't sell this item.");
			return;
		}
		int dq = getDefaultQuantity(item.getId());
		if (dq == -1 && generalStock == null) {
			player.getPackets().sendGameMessage("You can't sell this item to this shop.");
			return;
		}
		for (int i = 0; i < DonationItems.length; i++) {
			if (item.getId() == DonationItems[i][0]) {
				player.getPackets().sendGameMessage("You can't sell a Donator Item to a shop, try to sell it in the GE or to a player instead.");
				return;
			}
		}
		for (int i = 0; i < loyaltyPrices.length; i++) {
			if (item.getId() == loyaltyPrices[i][0]) {
				player.getPackets().sendGameMessage("You can't sell a Loyalty Reward to a shop, try to sell it in the GE or to a player instead.");
				return;
			}
		}
		for (int i = 0; i < Voteprices.length; i++) {
			if (item.getId() == Voteprices[i][0]) {
				player.getPackets().sendGameMessage("You can't sell a Voting Reward to a shop, try to sell it in the GE or to a player instead.");
				return;
			}
		}
		int price = getSellPrice(item, dq);
		int numberOff = player.getInventory().getItems().getNumberOf(originalId);
		if (quantity > numberOff)
			quantity = numberOff;
		if (!addItem(item.getId(), quantity)) {
			player.getPackets().sendGameMessage("Shop is currently full.");
			return;
		}
		player.getInventory().deleteItem(originalId, quantity);
		refreshShop();
		resetSelected(player);
		if (price == 0)
			return;
		player.getInventory().addItemMoneyPouch(new Item(money, price * quantity));
	}

	public void sendValue(Player player, int slotId) {
		if (player.getInventory().getItemsContainerSize() < slotId)
			return;
		Item item = player.getInventory().getItem(slotId);
		if (item == null)
			return;
		if (item.getDefinitions().isNoted())
			item = new Item(item.getDefinitions().getCertId(), item.getAmount());
		if (!ItemConstants.isTradeable(item) || item.getId() == money) {
			player.getPackets().sendGameMessage("You can't sell this item.");
			return;
		}
		int dq = getDefaultQuantity(item.getId());
		if (dq == -1 && generalStock == null) {
			player.getPackets().sendGameMessage("You can't sell this item to this shop.");
			return;
		}
		int price = getSellPrice(item, dq);
		player.getPackets().sendGameMessage(item.getDefinitions().getName() + ": shop will buy for: " + price + " " + ItemDefinitions.getItemDefinitions(money).getName().toLowerCase() + ". Right-click the item to sell.");
	}

	public int getDefaultQuantity(int itemId) {
		for (int i = 0; i < mainStock.length; i++)
			if (mainStock[i].getId() == itemId)
				return defaultQuantity[i];
		return -1;
	}

	public void resetSelected(Player player) {
		player.getTemporaryAttributes().remove("ShopSelectedSlot");
		player.getVarsManager().sendVar(2563, -1);
	}

	public void sendInfo(Player player, int slotId, boolean inventory) {
		if (!inventory && slotId >= getStoreSize())
			return;
		Item item = inventory ? player.getInventory().getItem(slotId) : slotId >= mainStock.length ? generalStock[slotId - mainStock.length] : mainStock[slotId];
		if (item == null)
			return;
		if (item.getDefinitions().isNoted())
			item = new Item(item.getDefinitions().getCertId(), item.getAmount());
		if (inventory && (!ItemConstants.isTradeable(item) || item.getId() == money)) {
			player.getPackets().sendGameMessage("You can't sell this item.");
			resetSelected(player);
			return;
		}
		for (int i = 0; i < DonationItems.length; i++) {
			if (item.getId() == DonationItems[i][0]) {
				player.getPackets().sendGameMessage("" + item.getDefinitions().getName() + ": shop will sell for <col=FF0000>" + DonationItems[i][1] + "</col> DCredits.");
				player.getVarsManager().sendVar(2564, DonationItems[i][1]);
				return;
			}
		}
		for (int i = 0; i < loyaltyPrices.length; i++) {
			if (item.getId() == loyaltyPrices[i][0]) {
				player.getPackets().sendGameMessage("" + item.getDefinitions().getName() + " costs <col=008000>" + loyaltyPrices[i][1] + "</col> loyalty points.");
				player.getVarsManager().sendVar(2564, loyaltyPrices[i][1]);
				return;
			}
		}
		for (int i = 0; i < Voteprices.length; i++) {
			if (item.getId() == Voteprices[i][0]) {
				player.getPackets().sendGameMessage("" + item.getDefinitions().getName() + " costs <col=FF0000>" + Voteprices[i][1] + "</col> voting points.");
				player.getVarsManager().sendVar(2564, Voteprices[i][1]);
				return;
			}
		}
		resetTransaction(player);
		player.getTemporaryAttributes().put("ShopSelectedSlot", slotId);
		player.getTemporaryAttributes().put("ShopSelectedInventory", inventory);
		player.getVarsManager().sendVar(2561, inventory ? 93 : generalStock != null ? 139 : MAIN_STOCK_ITEMS_KEY); // inv key
		player.getVarsManager().sendVar(2562, item.getId());
		player.getVarsManager().sendVar(2563, slotId);
		player.getPackets().sendGlobalString(362, ItemExamines.getExamine(item));
		player.getPackets().sendGlobalConfig(1876, item.getDefinitions().isWearItem() ? 0 : -1); // TODO item  pos or usage if has one, setting 0 to allow see stats
		int price = inventory ? getSellPrice(item, getDefaultQuantity(item.getId())) : getBuyPrice(item, slotId >= mainStock.length ? 0 : defaultQuantity[slotId]);
		player.getPackets().sendGameMessage(item.getDefinitions().getName() + ": shop will " + (inventory ? "buy" : "sell") + " for: " + price + " " + ItemDefinitions.getItemDefinitions(money).getName().toLowerCase());
	}

	public int getBuyPrice(Item item, int dq) {
		switch (money) {
		case 24444: // TROHPY
			if (item.getId() >= 24450 && item.getId() <= 24454)
				return 30 + (item.getId() - 24450) * 5;
			if (item.getId() >= 24455 && item.getId() <= 24457)
				return 1500;
			break;
		default:
			int price = GrandExchange.getPrice(item.getId());
			price = GrandExchange.getPrice(item.getId());
			if (price > 0)
				return price;
			if (item.getDefinitions().hasShopPriceAttributes())
				return 99000;
			price = GrandExchange.getPrice(item.getId());
			return Math.max(price, 1);

		}
		return 1;
	}


	public int getSellPrice(Item item, int dq) {
		int price = getBuyPrice(item, dq);
		price = getBuyPrice(item, dq);
		if (price > 0)
			return price / 2;
		return price / 2;

	}

	public void sendExamine(Player player, int slotId) {
		if (slotId >= getStoreSize())
			return;
		Item item = slotId >= mainStock.length ? generalStock[slotId - mainStock.length] : mainStock[slotId];
		if (item == null)
			return;
		player.getPackets().sendGameMessage(ItemExamines.getExamine(item));
	}

	public void refreshShop() {
		for (Player player : viewingPlayers) {
			sendStore(player);
			player.getPackets().sendIComponentSettings(620, 25, 0, getStoreSize() * 6, 1150);
		}
	}

	public int getStoreSize() {
		return mainStock.length + (generalStock != null ? generalStock.length : 0);
	}

	public void sendStore(Player player) {
		Item[] stock = new Item[mainStock.length + (generalStock != null ? generalStock.length : 0)];
		System.arraycopy(mainStock, 0, stock, 0, mainStock.length);
		if (generalStock != null)
			System.arraycopy(generalStock, 0, stock, mainStock.length, generalStock.length);
		player.getPackets().sendItems(generalStock != null ? 139 : MAIN_STOCK_ITEMS_KEY, stock);
	}

}